<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<script>

  /**
   * `Polymer.dom.flush()` causes any asynchronously queued actions to be
   * flushed synchronously. It should be used sparingly as calling it frequently
   * can negatively impact performance since work is often deferred for
   * efficiency. Calling `Polymer.dom.flush()` is useful, for example, when
   * an element has to measure itself and is unsure about the state of its
   * internal or compoased DOM.
   */
  Polymer.Base.mixin(Polymer.dom, {

    _flushGuard: 0,
    _FLUSH_MAX: 100,
    _needsTakeRecords: !Polymer.Settings.useNativeCustomElements,
    _debouncers: [],
    _staticFlushList: [],
    _finishDebouncer: null,

    // flush and debounce exposed as statics on Polymer.dom
    flush: function() {
      this._flushGuard = 0;
      this._prepareFlush();
      while (this._debouncers.length && this._flushGuard < this._FLUSH_MAX) {
        // Avoid using an index in this loop to ensure flush is safe to be
        // called reentrantly from a debouncer callback being flushed
        while (this._debouncers.length) {
          this._debouncers.shift().complete();
        }
        // clear the list of debouncers
        if (this._finishDebouncer) {
          this._finishDebouncer.complete();
        }
        this._prepareFlush();
        this._flushGuard++;
      }
      if (this._flushGuard >= this._FLUSH_MAX) {
        console.warn('Polymer.dom.flush aborted. Flush may not be complete.')
      }
    },

    _prepareFlush: function() {
      // TODO(sorvell): There is currently not a good way
      // to process all custom elements mutations under SD polyfill because
      // these mutations may be inside shadowRoots.
      // again make any pending CE mutations that might trigger debouncer
      // additions go...
      if (this._needsTakeRecords) {
        CustomElements.takeRecords();
      }
      for (var i=0; i < this._staticFlushList.length; i++) {
        this._staticFlushList[i]();
      }
    },

    // add to the static list of methods to call when flushing
    addStaticFlush: function(fn) {
      this._staticFlushList.push(fn);
    },

    // remove a function from the static list of methods to call when flushing
    removeStaticFlush: function(fn) {
      var i = this._staticFlushList.indexOf(fn);
      if (i >= 0) {
        this._staticFlushList.splice(i, 1);
      }
    },

    addDebouncer: function(debouncer) {
      this._debouncers.push(debouncer);
      // ensure the list of active debouncers is cleared when done.
      this._finishDebouncer = Polymer.Debounce(this._finishDebouncer,
        this._finishFlush);
    },

    _finishFlush: function() {
      Polymer.dom._debouncers = [];
    }

  });

</script>